<?php

namespace App\Winged\Backend\Oss;


use OSS\OssClient;
use OSS\Core\OssException;
use Psr\Log\InvalidArgumentException;

/**
 * Class OSS
 * @package App\Winged\Backend\Oss
 * useage
 * Oss::publicUploadContent(Str::random(32) . '.png' , file_get_contents('./1.png')); // 上传流 回来的是地址
 * Oss::publicUploadFile(Str::random(32) . '.png' , './1.png'); //上传文件 回来 的是地址
 *  // 签名 oss 使用方法 .
 * Oss::plugin('sign')->doSign('k8zDiWE2GAqVRH3YdNerX2iNrth5Xgul.png'); // 回来的是地址url
 */
class OSS
{

    public static $instance;

    public $bucket;

    public $ossClient;

    public static $plugins = [];

    public static function getOssClient(OssConfig $config)
    {
        try {
            $ossClient = new OssClient($config->accessKeyId, $config->accessKeySecret, $config->endpoint, false);
        } catch (OssException $e) {
            return null;
        }
        return $ossClient;
    }

    /**
     * 获取插件
     */
    public function __get($name)
    {
        $name = ucfirst($name);
        if (isset(self::$plugins[$name])) {
            return self::$plugins[$name];
        }
        return $this->installPlugin($name);
    }


    public static function test($name)
    {
        self::prepare();

    }

    /**
     * 获取插件
     */
    public static function plugin($name = null)
    {
        self::prepare();
        if ($name === null) {
            return self::$plugins;
        }
        return self::$instance->{$name};
    }

    /**
     * 安装插件
     */
    private function installPlugin($name)
    {
        $klass = "App\\Winged\\Backend\\Oss\\Plugins\\{$name}";
        if (!class_exists($klass)) {
            throw new InvalidArgumentException('Oss插件不存在 , 类名:' . $klass);
        }
        if ($this->ossClient === null) {
            $config          = new OssConfig(true);
            $this->ossClient = $this->getOssClient($config);
            $this->setBucket($config->bucket);
        }
        $plugin = new $klass();
        $plugin->install($this->ossClient, $this->bucket);
        self::$plugins[$name] = $plugin;
        return self::$plugins[$name];
    }


    /**
     * 获取实例 默认是外网
     * @return OSS
     */
    public static function instance()
    {
        if (self::$instance != null) {
            return self::$instance;
        }
        self::$instance            = new self();
        $config                    = new OssConfig(false);
        self::$instance->ossClient = self::$instance->getOssClient($config);
        self::$instance->setBucket($config->bucket);
        return self::$instance;
    }

    /**
     * 内网
     */
    public static function internelInstance()
    {
        if (self::$instance != null) {
            return self::$instance;
        }
        self::$instance            = new self();
        $config                    = new OssConfig(true);
        self::$instance->ossClient = self::$instance->getOssClient($config);
        self::$instance->setBucket($config->bucket);
        return self::$instance;
    }



    /**
     * 设置存储篮子
     * @param $bucket
     */
    public function setBucket($bucket)
    {
        $this->bucket = $bucket;
    }

    /**
     * $result ['info'] 包含如下返回值
     *     url => http://xxx.png
     *     http_code => 200 ...
     * 如果是上传的结果，直接返回地址。
     * 其他情况鸳鸯返回
     * 解析结果集
     */
    public static function parseResult($result)
    {
        if (is_array($result)) {
            if (isset($result['info'])) {
                if (isset($result['info']['http_code']) &&
                    isset($result['info']['url']) &&
                    $result['info']['http_code'] == 200
                ) {
                    return $result['info']['url'];
                } else {
                    return false;
                }
            } else {
                return $result; // todo 这种情况目前未知
            }
        } else {
            return $result;
        }
    }

    /**
     * 预先准备好本身对象
     */
    public static function prepare($internel = false)
    {
        // 如果是内网的话返回内网单利
        if($internel){
            return self::internelInstance();
        }
        self::instance();
    }

    /**
     * 使用外网上传流数据
     * @param $filename     文件名称
     * @param $content    流
     * @return mixed 返回地址
     */
    public static function publicUploadContent($filename, $content)
    {
        self::prepare(false);
        return self::parseResult(self::$instance->ossClient->putObject(self::$instance->bucket,
            $filename,
            $content
        ));
    }

    /**
     * 使用外网上传文件
     * @param $filename     文件名称
     * @param $path   文件本地路劲
     * @return mixed 返回地址
     */
    public static function publicUploadFile($filename, $path)
    {
        self::prepare(false);
        return self::parseResult(self::$instance->ossClient->uploadFile(
            self::$instance->bucket,
            $filename,
            $path
        ));
    }

    /**
     * 下载流当做本地变量
     * @param $filename
     * @return mixed 返回流数据
     */
    public static function downloadObject($filename)
    {
        self::prepare();
        return self::parseResult(self::$instance->ossClient->getObject(
            self::$instance->bucket,
            $filename
        ));
    }

    /**
     * 下载文件
     * @param $filename
     * @param $options 本地的路劲文件名称
     * @return mixed 空字符串 .
     */
    public static function downloadFile($filename, $options)
    {
        // 暂时没调试，先这样
        $options = array(
            OssClient::OSS_FILE_DOWNLOAD => $options,
        );
        self::prepare();
        return self::parseResult(self::$instance->ossClient->getObject(
            self::$instance->bucket,
            $filename,
            $options
        ));
    }

    /**
     * 创建虚拟目录
     * @param $dirname
     */
    public static function createObjectDir($dirname)
    {
        self::prepare();
        return self::parseResult(self::$instance->ossClient->createObjectDir(
            self::$instance->bucket,
            $dirname
        ));
    }

    /**
     * 列出当前bucket所有的目录和文件
     */
    public static function listAllObjects($options = [])
    {
        self::prepare();
        if (!isset($options ['delimiter'])) {
            $options ['delimiter'] = '/';
        }
        if (!isset($options['prefix'])) {
            $options['prefix'] = '';
        }
        if (!isset($options['max-keys'])) {
            $options['max-keys'] = 15;
        }
        if (!isset($options['marker'])) {
            $options['marker'] = '';
        }
        try {
            $object = self::$instance->ossClient->listObjects(self::$instance->bucket, $options);
        } catch (OssException $e) {
            throw new OssException($e->getMessage());
        }
        // todo 待调试
//        $nextMarker = $object->getNextMarker();
//        $listObject = $object->getObjectList();
//        $listPrefix = $object->getPrefixList();
        return $object;
    }


}
